package com.bwton.msx.ccb.service.auth;

import com.bwton.msx.ccb.service.api.AuthApiService;
import com.bwton.msx.ccb.service.api.annotations.FaceOperate;
import com.bwton.msx.ccb.service.api.response.ApiResponse;
import com.bwton.msx.ccb.service.api.response.FaceQueryResult;
import com.bwton.msx.ccb.service.api.response.IgnoreResult;
import com.bwton.msx.ccb.service.api.response.LoginResult;
import com.bwton.msx.ccb.service.api.response.RegisterResult;
import com.bwton.msx.ccb.service.api.response.SignChannelQueryResult;
import com.bwton.msx.ccb.service.api.response.SmsTokenResult;
import com.bwton.msx.ccb.service.api.response.UserInfoResult;
import com.bwton.msx.ccb.service.user.UserManager;
import com.bwton.msx.ccb.utils.Configuration;

import java.util.HashMap;
import java.util.Map;

import io.reactivex.Notification;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Function3;
import io.reactivex.schedulers.Schedulers;

/**
 * 用户业务操作相关
 */
public class AuthService {
    private final AuthApiService apiService;
    private static final String device_info_str = "{\"appVersion\":\"1.0.5\",\"appName\":\"长春E出行\",\"latitude\":\"\",\"imsi\":\"\",\"usedDisk\":\"85454\",\"systemVersion\":\"New Version:29\",\"appVersionCode\":\"49\",\"totalDisk\":\"230871\",\"city_name\":\"长春\",\"macAddress\":\"A8:9C:ED:B3:BE:16\",\"mobileBrand\":\"Xiaomi\",\"sourceIp\":\"fe80::b070:6aff:febd:e507%dummy0\",\"sourceType\":\"1\",\"imei\":\"00000000-2ab4-a945-ffff-ffffcbe41f7b\",\"longitude\":\"\"}";

    public AuthService(AuthApiService authApiService) {
        this.apiService = authApiService;
    }

    /**
     * 发送注册验证码
     *
     * @param phone 手机号
     * @return
     */
    public Observable<ApiResponse<IgnoreResult>> sendRegisterSms(String phone) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("mobile_phone", phone);
        params.put("sms_code_len", "4");
        params.put("sms_type", "1");
        return apiService.sendRegisterSms(params);
    }

    /**
     * 发送登录验证码
     *
     * @param phone 手机号
     * @return
     */
    public Observable<ApiResponse<IgnoreResult>> sendLoginSms(String phone) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("mobile_phone", phone);
        params.put("sms_code_len", "4");
        params.put("sms_type", "0");
        return apiService.sendRegisterSms(params);
    }

    /**
     * 发送修改密码验证码
     *
     * @param phone 手机号
     * @return
     */
    public Observable<ApiResponse<IgnoreResult>> sendPasswordSms(String phone) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("mobile_phone", phone);
        params.put("sms_code_len", "4");
        params.put("sms_type", "2");
        return apiService.sendRegisterSms(params);
    }

    /**
     * 注册用户
     *
     * @param phone
     * @param sms
     * @return
     */
    public Observable<ApiResponse<RegisterResult>> register(String phone, String sms) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("mobile_phone", phone);
        params.put("sms_code", sms);
        params.put("place_code", Configuration.PLACE_CODE);
        params.put("verify_type", "sms_code_verify");
        return apiService.register(params);
    }

    /**
     * 验证码登录
     *
     * @param phone
     * @param sms
     * @return
     */
    public Observable<ApiResponse<LoginResult>> loginBySms(String phone, String sms) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("mobile_phone", phone);
        params.put("sms_code", sms);
        params.put("device_info_str", device_info_str);
        return apiService.loginBySms(params);
    }
    /**
     * 密码登录
     *
     * @param phone
     * @param password
     * @return
     */
    public Observable<ApiResponse<LoginResult>> loginByPassword(String phone, String password) {
        Map<String, String> param = new HashMap<>();
        param.put("mobile_phone", phone);
        param.put("password", password);
        param.put("device_info_str", device_info_str);
        return apiService.loginByPassword(param);
    }
    /**
     * 修改密码:
     * 1.通过sms获取到sms_token
     * 2.发送密码
     *
     * @param phone
     * @param sms
     * @return
     */
    public Observable<ApiResponse<IgnoreResult>> setPassword(String phone, String sms, String password) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("mobile_phone", phone);
        params.put("sms_code", sms);
        params.put("device_info_str", device_info_str);
        return getSmsToken(phone,sms)
                .flatMap(new Function<ApiResponse<SmsTokenResult>, ObservableSource<ApiResponse<IgnoreResult>>>() {
                    @Override
                    public ObservableSource<ApiResponse<IgnoreResult>> apply(ApiResponse<SmsTokenResult> loginResultApiResponse) throws Exception {
                        if (loginResultApiResponse.isSuccess()){
                            Map<String, String> params = new HashMap<>();
                            params.put("mobile_phone", phone);
                            params.put("sms_token", loginResultApiResponse.getResult().sms_token);
                            params.put("new_password", password);
                            return apiService.setPassword(params);
                        }else {
                            throw new Exception("token获取失败!");
                        }
                    }
                });
    }

    private Observable<ApiResponse<SmsTokenResult>> getSmsToken(String phone, String sms) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("mobile_phone", phone);
        params.put("sms_code", sms);
        params.put("sms_type", "2");
        return apiService.smsToken(params);
    }

    /**
     * 查询用户状态
     */
    public void updateUserState(String phone, String uid, String unionId) {
        Disposable disposable = Observable.zip(queryFace(), querySignResult(unionId), queryBaseInfo(phone, uid), new Function3<ApiResponse<FaceQueryResult>, ApiResponse<SignChannelQueryResult>, ApiResponse<UserInfoResult>, Boolean>() {
                    @Override
                    public Boolean apply(ApiResponse<FaceQueryResult> faceQueryResultApiResponse, ApiResponse<SignChannelQueryResult> signChannelQueryResultApiResponse, ApiResponse<UserInfoResult> userInfoResultApiResponse) throws Exception {
                        UserManager.getInstance().update(user -> {
                            if (userInfoResultApiResponse.success) {
                                UserInfoResult.User info = userInfoResultApiResponse.getResult().getUser();
                                user.state.setEnableCode(info.getObtain_code_status() == 1);
                                user.state.setEnableRealName(info.getAuth_status() == 1);
                            }
                            if (faceQueryResultApiResponse.success) {
                                FaceQueryResult result = faceQueryResultApiResponse.getResult();
                                user.state.setEnableFace(!"0".equals(result.getFace_status()));
                                user.state.setFaceState(result.getFace_status());
                            }
                            if (signChannelQueryResultApiResponse.success) {
                                SignChannelQueryResult result = signChannelQueryResultApiResponse.getResult();
                                user.state.setEnableSign("1".equals(result.getStatus()));
                            }
                        });
                        return true;
                    }
                }).subscribeOn(Schedulers.io())
                .subscribe(v -> {
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        throwable.printStackTrace();
                    }
                });
    }

    private Observable<ApiResponse<FaceQueryResult>> queryFace() {
        Map<String, String> params = new HashMap<>();
        params.put("card_id", "A32043204");
        return apiService.queryFace(params);
    }

    private Observable<ApiResponse<SignChannelQueryResult>> querySignResult(String union_id) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("union_id", union_id);
        params.put("channel_product_code", "UNIONPAY_UNBQP");
        params.put("business_type", "");
        return apiService.querySignResult(params);
    }

    private Observable<ApiResponse<UserInfoResult>> queryBaseInfo(String phone, String uid) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("mobile_phone", phone);
        params.put("user_id", uid);
        params.put("place_code", Configuration.PLACE_CODE);
        params.put("open_id", "21000051");
        params.put("query_type", "1");
        return apiService.queryInfo(params).doOnEach(new Consumer<Notification<ApiResponse<UserInfoResult>>>() {
            @Override
            public void accept(Notification<ApiResponse<UserInfoResult>> apiResponseNotification) throws Exception {
                if (apiResponseNotification.isOnNext()) {
                    ApiResponse<UserInfoResult> apiResponse = apiResponseNotification.getValue();
                    if (apiResponse.success) {
                        UserManager.getInstance().update(user -> {
                            UserInfoResult result = apiResponse.getResult();
                            user.phone = result.getUser().getMobile_phone();
                            user.userId = result.getUser().getUser_id();
                            user.unionId = result.getUser().getUnion_id();
                        });
                    }
                }
            }
        });
    }

    /**
     * 开通人脸
     *
     * @param face 人脸的base64格式数据
     * @return
     */
    public Observable<ApiResponse<IgnoreResult>> openFace(String face) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("card_id", "A32043204");
        params.put("type", "");
        params.put("face_image", face);
        params.put("service_id", "01");
        return openCode().flatMap(ignoreResultApiResponse -> apiService.faceOpen(params));
    }

    /**
     * 开通乘车码服务
     *
     * @return
     */
    private Observable<ApiResponse<IgnoreResult>> openCode() {
        Map<String, String> params = new HashMap<>();
        params.put("card_id", "A32043204");
        params.put("business_type", "1");
        params.put("service_id", "01");
        return apiService.registerCode(params);
    }

    /**
     * 发送签约短信验证码
     *
     * @param phone                手机号
     * @param unionId              uid
     * @param channel_product_code 渠道号
     * @param channel_merchant_id  渠道id
     * @param name                 姓名
     * @param cardNo               银行卡号
     * @param idCard               身份证号
     * @return
     */
    public Observable<ApiResponse<IgnoreResult>> sendSignSms(String phone, String unionId, String channel_product_code, String channel_merchant_id,
                                                             String name, String cardNo, String idCard) {
        Map<String, String> params = new HashMap<>();
        params.put("union_id", unionId);
        params.put("channel_product_code", channel_product_code);
        params.put("channel_merchant_id", channel_merchant_id);
        params.put("name", name);
        params.put("cert_no", idCard);
        params.put("cert_type", "01");
        params.put("bank_card_no", cardNo);
        params.put("mobile_phone", phone);
        return apiService.sendSignSms(params);
    }

    /**
     * 银行卡签约
     *
     * @return
     */
    public Observable<ApiResponse<Object>> signByCard(String phone, String unionId, String channel_product_code, String channel_merchant_id,
                                                      String name, String cardNo, String idCard, String sms) {
        Map<String, String> params = new HashMap<>();
        params.put("union_id", unionId);
        params.put("channel_product_code", channel_product_code);
        params.put("channel_merchant_id", channel_merchant_id);
        params.put("name", name);
        params.put("cert_no", idCard);
        params.put("cert_type", "01");
        params.put("bank_card_no", cardNo);
        params.put("mobile_phone", phone);
        params.put("sms_code", sms);
        params.put("scene_code", "01000001");
        return apiService.signByCard(params);
    }

    /**
     * 开通乘车码服务
     *
     * @return
     */
    public Observable<ApiResponse<IgnoreResult>> faceOperate(@FaceOperate String action) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("card_id", "A32043204");
        params.put("service_id", "01");
        params.put("operate_type", action);
        return apiService.faceOperate(params);
    }

    /**
     * 用户注销1.人脸注销 2.签约取消 3.账号注销
     *
     * @return
     */
    public Observable<ApiResponse<IgnoreResult>> unRegUser(String union_id) {
        return Observable.zip(closeFace(), closeSign(), new BiFunction<ApiResponse<IgnoreResult>, ApiResponse<IgnoreResult>, Boolean>() {
                    @Override
                    public Boolean apply(ApiResponse<IgnoreResult> ignoreResultApiResponse, ApiResponse<IgnoreResult> ignoreResultApiResponse2) throws Exception {

                        return true;
                    }
                }).flatMap(new Function<Boolean, ObservableSource<ApiResponse<IgnoreResult>>>() {
                    @Override
                    public ObservableSource<ApiResponse<IgnoreResult>> apply(Boolean aBoolean) throws Exception {
                        return closeUser(union_id);
                    }
                }).observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io());
    }

    private Observable<ApiResponse<IgnoreResult>> closeFace() {
        return faceOperate("3");
    }

    private Observable<ApiResponse<IgnoreResult>> closeSign() {
        Map<String, String> params = new HashMap<String, String>();
        params.put("union_id", "A32043204");
        params.put("account_no", "1372864037729132544");
        params.put("channel_product_code", "ALI_SIGN_PAY");
        params.put("channel_merchant_id", "11173317");
        return apiService.unSign(params);
    }

    private Observable<ApiResponse<IgnoreResult>> closeUser(String union_id) {
        Map<String, String> user = new HashMap<String, String>();
        user.put("union_id", union_id);
        return apiService.closeUser(user);
    }

}
